using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using BestHTTP.WebSocket;
using LitJson;
using NativeFileBrowser;
using UnityEngine;
using UnityEngine.Networking;


[System.Serializable]
public class UrlEntity
{
    public string importStlUrl;  
    public string spartaUrl;
    public string convertUrl;
    public string calculateUrl;
}


public class AirManager : MonoBehaviour
{
    public static AirManager instance;
    //测试地址：http://103.164.63.52:8000/api/swagger#/
    // 请求接口：http://103.164.63.52:8000/api/sparta 。 方法： POST
    //查看结果 ，访问静态资源： http://103.164.63.52:8000/api/static/in.circle
    //第一个按钮 导入stl 文件，接口： http://103.164.63.52:8000/api/sparta/import 
    //上传完成后在静态资源访问： http://103.164.63.52:8000/api/static/Upload/上传的文件名
    // AirData airData = new AirData();
    [SerializeField] private MeshCreatePanel meshCreatePanel;
    [SerializeField] private PretreatmentPanel pretreatmentPanel;
    [SerializeField] private CalculatePanel calculatePanel;
    [SerializeField] private DialogPanel dialogPanel;
  
    
    private static string postSeverUrl ;

    private static string importUrl ;

    private static string convertUrl;
    private static string calculateUrl;

    private WebSocket webSocket_Convert;
    private WebSocket webSocket_Calculate;
    private string uploadFileName = "";//上传的文件名
    // Start is called before the first frame update
    void Start()
    {
        instance = this;
        string filePath = Path.Combine(Application.streamingAssetsPath,"url_data.txt");
        string jsonData = File.ReadAllText(filePath);
        
        var comJson_ZiMuZu = JsonUtility.FromJson<UrlEntity>(jsonData);
        postSeverUrl = comJson_ZiMuZu.spartaUrl;
        importUrl = comJson_ZiMuZu.importStlUrl;
        calculateUrl = comJson_ZiMuZu.calculateUrl;
        convertUrl = comJson_ZiMuZu.convertUrl;
        Debug.Log("spartaUrl: " + comJson_ZiMuZu.spartaUrl);
        Debug.Log("importStlUrl: " + comJson_ZiMuZu.importStlUrl);
        Debug.Log("convertUrl: " + comJson_ZiMuZu.convertUrl);
        Debug.Log("calculateUrl: " + comJson_ZiMuZu.calculateUrl);
        InitWebSocket();
        InitWebSocket_Convert();
    }
  
    
    
    private AirData GetAirData()
    {
        AirData airData = new AirData();
        //网格参数
        airData.dimension = meshCreatePanel.GetSwithcModelValue();
        airData.create_box_x_max =meshCreatePanel.GetXmaxDomainValue();
        
        airData.create_box_x_min =meshCreatePanel.GetXminDomainValue();
        airData.create_box_y_max = meshCreatePanel.GetYmaxDomainValue();
        airData.create_box_y_min =meshCreatePanel.GetYminDomainValue();
        airData.create_box_z_max =meshCreatePanel.GetZmaxDomainValue();
        airData.create_box_z_min = meshCreatePanel.GetZminDomainValue();
    
        airData.create_grid_x = meshCreatePanel.GetXCreateGridNumValue();
        airData.create_grid_y = meshCreatePanel.GetYCreateGridNumValue();
        airData.create_grid_z = meshCreatePanel.GetZCreateGridNumValue();
        
        //预处理参数
        airData.boundary_xhi =pretreatmentPanel.GetBoundaryXhi();
        airData.boundary_xlo =pretreatmentPanel.GetBoundaryXlo();
        airData.boundary_yhi =pretreatmentPanel.GetBoundaryYhi();
        airData.boundary_ylo =pretreatmentPanel.GetBoundaryYlo();
        airData.boundary_zhi =pretreatmentPanel.GetBoundaryZhi();
        airData.boundary_zlo =pretreatmentPanel.GetBoundaryZlo();
        airData.global_fnum = pretreatmentPanel.GetGlobalFnum();
        airData.global_nrho =pretreatmentPanel.GetGlobalNrho();
    
        airData.surf_collide_type = pretreatmentPanel.GetSurfCollideType();
        airData.collide_alpha =pretreatmentPanel.GetCollideAlpha();
        airData.wall_temperature =pretreatmentPanel.GetWallTemperature();
        airData.reflectivity =pretreatmentPanel.GetReflectivity();

        airData.mixture_type_str = pretreatmentPanel.GetMixGasString();// pretreatmentPanel.GetMixGasDic();//
        airData.temperature = pretreatmentPanel.GetTemperature();
    
        airData.v_stream_x =pretreatmentPanel.GetStreamVX();
        airData.v_stream_y = pretreatmentPanel.GetStreamVY();
        airData.v_stream_z = pretreatmentPanel.GetStreamVZ();
    
        //计算参数
        airData.compute_speed = calculatePanel.GetComputeSpeed();
        airData.compute_thermo= calculatePanel.GetComputeThermo();
        airData.compute_heat = calculatePanel.GetComputeHeat();
    
        airData.time_step =calculatePanel.GetTimeStep();
        airData.run =calculatePanel.GetRun();
    
        airData.upload_stl_name = uploadFileName; //上传的文件名

        airData.is_dump_grid = true;

        airData.is_grid_to_paraview = true;
        airData.dump_grid_number = calculatePanel.GetDumpGridNumber();
        airData.dump_compute_speed = calculatePanel.GetComputeSpeed();
        airData.dump_compute_thermo = calculatePanel.GetComputeThermo();
        airData.dump_compute_heat = calculatePanel.GetDumpComputeHeat();
        airData.is_grid_coordinate = calculatePanel.GetIsGridCoordinate();
        
        return airData;
    }
    public async void SendData()
    {
        AirData airData = GetAirData();
        // string airDataString =JsonMapper.ToJson(airData);
        // string airDataString = JsonUtility.ToJson(airData);
        // Debug.Log("airData = "+airDataString);
        if(!CheckData(airData))
        {
            return;
        }
        // string airDataString =JsonMapper.ToJson(airData);
        string airDataString = JsonUtility.ToJson(airData);
        Debug.Log("airData = "+airDataString);
        try
        {
            string result = await HttpClientHelper.Post(postSeverUrl, airDataString);
            Console.WriteLine(result);
        }
        catch (Exception ex)
        {
            Console.WriteLine("错误：\n{0}", ex.Message);
        }
        
        SetWebData();
    }

  
    public bool CheckData(AirData airData)
    {
        if (string.IsNullOrEmpty(uploadFileName))
        {
            dialogPanel.Show("请先导入stl模型");
            return false;
        }
        if(string.IsNullOrEmpty(airData.create_box_x_min))
        {
            dialogPanel.Show("计算域 x 最小值不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.create_box_x_max))
        {
            dialogPanel.Show("计算域 x 最大值不能为空");
            return false;
        }
        if(float.Parse(airData.create_box_x_max) <= float.Parse(airData.create_box_x_min))
        {
            dialogPanel.Show("计算域 x 最大值必须大于最小值");
            return false;
        }
        
        if(string.IsNullOrEmpty(airData.create_box_y_min))
        {
            dialogPanel.Show("计算域 y 最小值不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.create_box_y_max))
        {
            dialogPanel.Show("计算域 y 最大值不能为空");
            return false;
        }
        if(float.Parse(airData.create_box_y_max) <= float.Parse(airData.create_box_y_min))
        {
            dialogPanel.Show("计算域 y 最大值必须大于最小值");
            return false;
        }
        
        if(string.IsNullOrEmpty(airData.create_box_z_min))
        {
            dialogPanel.Show("计算域 z 最小值不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.create_box_z_max))
        {
            dialogPanel.Show("计算域 z 最大值不能为空");
            return false;
        }
        if(float.Parse(airData.create_box_z_max) <= float.Parse(airData.create_box_z_min))
        {
            dialogPanel.Show("计算域 z 最大值必须大于最小值");
            return false;
        }
        
        if(string.IsNullOrEmpty(airData.create_grid_x))
        {
            dialogPanel.Show("网格生成 x 方向网格数量不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.create_grid_y))
        {
            dialogPanel.Show("网格生成 y 方向网格数量不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.create_grid_z))
        {
            dialogPanel.Show("网格生成 z 方向网格数量不能为空");
            return false;
        }
        
        if(string.IsNullOrEmpty(airData.global_fnum))
        {
            dialogPanel.Show("来流分子数密度 不能为空");
            return false;
        }
        
        if(string.IsNullOrEmpty(airData.global_nrho))
        {
            dialogPanel.Show("真实与模拟分子数比 不能为空");
            return false;
        }

        if (string.Equals(airData.surf_collide_type, "diffuse"))
        {
            if(string.IsNullOrEmpty(airData.wall_temperature))
            {
                dialogPanel.Show("壁面温度 不能为空");
                return false;
            }
            if(string.IsNullOrEmpty(airData.reflectivity))
            {
                dialogPanel.Show("反射比例 不能为空");
                return false;
            }
        }
        if(string.IsNullOrEmpty(airData.temperature))
        {
            dialogPanel.Show("温度 不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.v_stream_x))
        {
            dialogPanel.Show("速度 Vx 不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.v_stream_y))
        {
            dialogPanel.Show("速度 Vy 不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.v_stream_z))
        {
            dialogPanel.Show("速度 Vz 不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.time_step))
        {
            dialogPanel.Show("时间步长 不能为空");
            return false;
        }
        if(string.IsNullOrEmpty(airData.run))
        {
            dialogPanel.Show("计算步数 不能为空");
            return false;
        }
        return true;
    }
    public void OpenURL()
    {
        Application.OpenURL("http://103.164.63.52:8000/api/swagger#/");
    }

    public async void ImportFile(string extension)
    {
        
        FolderBrowserHelper.SelectFile((msg) =>
        {
            if (msg.success )
            {
                if(string.Equals("stl", extension))
                    uploadFileName =  Path.GetFileName(msg.msg);
                // airData.upload_stl_name = Path.GetFileName(msg.path);
                AirImportData airImportData = new AirImportData();
                airImportData.file = msg.msg;
                Debug.Log("Selected: " + msg.msg + "\n");
                uploadFile(airImportData.file, extension);
            }
        });
    }

    public  async Task uploadFile(string filePath,string extension)
    {
        try
        {
            using (var client = new HttpClient())
            {
                using (var content = new MultipartFormDataContent())
                using (var fileStream = File.OpenRead(filePath))
                {
                    var streamContent = new StreamContent(fileStream);
                    content.Add(streamContent, "file", Path.GetFileName(filePath));
                    content.Add(streamContent, "type", extension);
                    var response = await client.PostAsync(importUrl, content);
                    response.EnsureSuccessStatusCode();

                    Console.WriteLine(await response.Content.ReadAsStringAsync());
                    Console.WriteLine("Success! File uploaded.");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Error! " + ex.Message);
        }
    }
    
    private void InitWebSocket()
    {
        if (webSocket_Calculate == null)
        {
            webSocket_Calculate = new WebSocket(new Uri(calculateUrl));
            webSocket_Calculate.OnOpen += OnOpen;
            webSocket_Calculate.OnMessage += OnMessageReceived;
            webSocket_Calculate.OnClosed += OnClosed;
            webSocket_Calculate.OnError += OnError;

            // Start connecting to the server
            webSocket_Calculate.Open();
        }
        
    }
    void OnOpen(WebSocket ws)
    {
        Debug.Log("-WebSocket Open!\n");
        if(calculatePanel.gameObject.activeSelf)
            calculatePanel.AppendData("WebSocket Open!");
    }

    public void SetWebData()
    {
        if (webSocket_Calculate == null)
        {
            InitWebSocket();
        }
        AirData airData = GetAirData();;
        string airDataString = JsonUtility.ToJson(airData);
        Debug.Log("-WebSocket Send!\n"+airDataString);
        webSocket_Calculate.Send(airDataString);
    }
    /// <summary>
    /// Called when we received a text message from the server
    /// </summary>
    void OnMessageReceived(WebSocket ws, string message)
    {
        Debug.Log(string.Format("-Message received: {0}\n", message));
        calculatePanel.AppendData(message);
    }

    /// <summary>
    /// Called when the web socket closed
    /// </summary>
    void OnClosed(WebSocket ws, UInt16 code, string message)
    {
        Debug.Log(string.Format("-WebSocket closed! Code: {0} Message: {1}\n", code, message));
        webSocket_Calculate = null;
    }

    /// <summary>
    /// Called when an error occured on client side
    /// </summary>
    void OnError(WebSocket ws, Exception ex)
    {
        string errorMsg = string.Empty;
#if !UNITY_WEBGL || UNITY_EDITOR
        if (ws.InternalRequest.Response != null)
            errorMsg = string.Format("Status Code from Server: {0} and Message: {1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message);
#endif

        Debug.Log(string.Format("-An error occured: {0}\n", (ex != null ? ex.Message : "Unknown Error " + errorMsg)));

        webSocket_Calculate = null;
    }
    

    #region 可视模式转换 WebSocket

    /// <summary>
    /// 
    /// </summary>

    private void InitWebSocket_Convert()
    {
        
        if (webSocket_Convert == null)
        {
            webSocket_Convert = new WebSocket(new Uri(convertUrl));
            webSocket_Convert.OnOpen += OnOpen_Convert;
            webSocket_Convert.OnMessage += OnMessageReceived_Convert;
            webSocket_Convert.OnClosed += OnClosed_Convert;
            webSocket_Convert.OnError += OnError_Convert;

            // Start connecting to the server
            webSocket_Convert.Open();
        }
    }
    void OnOpen_Convert(WebSocket ws)
    {
        Debug.Log("-Convert WebSocket Open!\n");
        if(calculatePanel.gameObject.activeSelf)
            calculatePanel.AppendData(" Convert WebSocket Open!");
    }
    public  void ConvertData()
    {
        ConvertData convertData = new ConvertData();
        string convertDataString = JsonUtility.ToJson(convertData);
        if (webSocket_Calculate == null)
        {
            InitWebSocket_Convert();
        }
        webSocket_Convert.Send(convertDataString);
    }
    /// <summary>
    /// Called when we received a text message from the server
    /// </summary>
    void OnMessageReceived_Convert(WebSocket ws, string message)
    {
        Debug.Log(string.Format("-Convert Message received: {0}\n", message));
        if(calculatePanel.gameObject.activeSelf)
            calculatePanel.AppendData(message);
    }

    /// <summary>
    /// Called when the web socket closed
    /// </summary>
    void OnClosed_Convert(WebSocket ws, UInt16 code, string message)
    {
        Debug.Log(string.Format("-webSocket_Convert closed! Code: {0} Message: {1}\n", code, message));
        webSocket_Convert = null;
    }

    /// <summary>
    /// Called when an error occured on client side
    /// </summary>
    void OnError_Convert(WebSocket ws, Exception ex)
    {
        string errorMsg = string.Empty;
#if !UNITY_WEBGL || UNITY_EDITOR
        if (ws.InternalRequest.Response != null)
            errorMsg = string.Format("Status Code from Server: {0} and Message: {1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message);
#endif

        Debug.Log(string.Format("-An error occured: {0}\n", (ex != null ? ex.Message : "Unknown Error " + errorMsg)));

        webSocket_Convert = null;
    }
    
    #endregion
}
